#    Supsta
#    Copyright (c) 2014 Sebastian Dufner
#
#    This file is part of Supsta.
#
#    Supsta is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    Supsta is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

require 'fileutils'

require 'supsta/application_utils'
require 'supsta/gimp/application'

module Supsta
  class Application
    include ApplicationUtils

    def initialize(fast: false, force: false)
      @fast, @force = fast, force
      @assets_dir = 'assets'
      @source_dir = 'textures'
      @gimp = Gimp::Application.new
    end

    attr_reader :project_path
    attr_reader :assets_dir
    attr_reader :source_dir

    def project_name; File::basename(project_path); end
    def assets_path; File::join(project_path, assets_dir); end
    def compile_path; File::join(project_path, project_name); end
    def source_path; File::join(project_path, source_dir); end
    def sm_textures_path
      File::join(@config[:starmade], 'data', 'textures', 'block')
    end
    def sm_originals_path
      File::join(sm_textures_path, 'Realistic', '256')
    end
    def sm_config_path
      File::join(@config[:starmade], 'data', 'config')
    end

    def new(project, options = {})
      @nvars = 0
      @project_path = project
      @config =
          {
            sizes: options[:sizes],
            workingsize: options[:workingsize],
            starmade: options[:starmade]
          }

      exit_now!("Cannot create project in #{@project_path}: file exists") if
        Dir::exists?(project_path) && !@force
      exit_now!("Discouraged project name: #{project_name}") if
        (project_name == @assets_dir || project_name == @source_dir) && !@force
      exit_now!('Omitting the path to StarMade is discouraged, --force to '
            .concat('override.')) unless options[:starmade]
      validate_sm_dir!

      mkdir project_path
      mkdir source_path
      mkdir assets_path
      mkdir compile_path
      create_compilations
      save_config

      do_upgrade

      Overlay_Inds.each do |i|
        filename = Overlay_Filename + '_'.concat(i.to_s)
        add(filename, project_path,
              {
                id: i,
                name: filename,
                overlay: true,
                numsides: 1,
                color: [1.0, 0.5, 0.0]
              })
      end

      puts 'Creating image files, this may take a while...'
      @gimp.execute
      dry project_path
    end

    def install(project_path = '.')
      @project_path = project_path

      print 'Installing texture pack...'
      FileUtils::rm_r File::join(sm_textures_path, project_name)
      FileUtils::cp_r(compile_path, File::join(sm_textures_path, project_name))
      puts ' Done.'
    end

    def add(block, project_path = '.', options = {})
      @project_path = project_path
      load_config unless @config

      options = (block_config.values
            .find {|b| b[:name].downcase == block.downcase} || {})
          .merge(options) if @config[:starmade]

      mkdir source_path
      dir = File::join(source_path, block)

      if options[:specialized]
        exit_now!("Cannot add a specialized version for texture #{block}, "
              .concat("create the unspecialized version first.")) unless
          Dir::exists?(dir)

        texture_config = {specialized: []}.merge!(read_texture_conf(block))
        specializations = texture_config[:specialized]

        options[:specialized].each do |size|
          exit_now!("Texture pack not configured for size #{size}") unless
            @config[:sizes].include?(size) || @force
        end
        options[:specialized].each do |size|
          specializations << size

          add_texture(
                dir, @config[:workingsize],
                options[:numsides], options[:color], options[:animated], size)
        end

        save_texture_conf(block, texture_config.to_yaml)
      else
        mkdir dir
        add_texture(dir, @config[:workingsize],
              options[:numsides], options[:color], options[:animated])
        save_texture_conf(block, options.merge(x_offset: 0, y_offset: 0))
      end
    end

    def compile(project_path = '.', options = {})
      @project_path = project_path
      load_config unless @config
      @files = nil if options.delete(:recompile)
      speed = @fast ? :fast_rgba : :best_compression

      @files ||= {}
      modfiles = modified_files
      return if modfiles.empty?
      puts "Found #{modfiles.size} modified files"

      load_compilations
      modfiles.each do |file, mtime|
        compile_texture file, hflip: options[:hflip]
      end
      @textures.each do |filename, sizes|
        sizes.each do |size, image|
          file = File::join(compile_path, size.to_s, filename)
          @gimp.message "Saving file: #{file}"
          image.save(file)
        end
      end
      @files.merge! modfiles

      @gimp.execute

      save_config
      puts 'Build finished!'

      install project_path if options[:install]
    end

    def watch(project_path = '.', options = {})
      puts 'Watching project; press Ctrl+C to stop.'

      while true
        compile project_path, options

        sleep 1
      end
    end

    def upgrade(project_path = '.')
      @project_path = project_path
      load_config unless @config

      do_upgrade
      @gimp.execute


      dry project_path
      puts 'Upgrade finished!'
    end

    def dry(project_path = '.')
      @project_path = project_path
      load_config unless @config

      @files ||= {}
      modfiles = modified_files
      @files.merge! modfiles

      save_config
    end
  end
end
